﻿////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// <copyright>Copyright 2008-2011 Andreas Huber Doenni</copyright>
// Distributed under the Microsoft Public License (Ms-PL).
// See accompanying file License.txt or copy at http://mews.codeplex.com/license.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mews.IO
{
    using System;
    using System.IO;

    /// <summary>Provides <see cref="Stream"/> utility methods.</summary>
    /// <threadsafety static="true" instance="false"/>
    public static class StreamHelper
    {
        internal static readonly byte[] LineBreak = { (byte)'\r', (byte)'\n' };

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>Reads all the bytes from <paramref name="origin"/> and writes them into
        /// <paramref name="destination"/>, using <paramref name="buffer"/> as temporary buffer.</summary>
        /// <exception cref="ArgumentNullException">One or more of the passed arguments equals <c>null</c>.</exception>
        /// <exception cref="ArgumentException"><paramref name="buffer"/>.<see cref="Array.Length"/> equals 0.
        /// </exception>
        /// <exception cref="ObjectDisposedException"><paramref name="origin"/> and/or <paramref name="destination"/>
        /// have been disposed.</exception>
        public static void Copy(Stream origin, Stream destination, byte[] buffer)
        {
            if (origin == null)
            {
                throw new ArgumentNullException("origin");
            }

            if (destination == null)
            {
                throw new ArgumentNullException("destination");
            }

            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }

            if (buffer.Length == 0)
            {
                throw new ArgumentException("Non-zero buffer length expected.", "buffer");
            }

            int read;

            while ((read = origin.Read(buffer, 0, buffer.Length)) > 0)
            {
                destination.Write(buffer, 0, read);
            }
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        internal static void WriteLineBreak(Stream stream)
        {
            stream.Write(LineBreak, 0, LineBreak.Length);
        }

        /// <summary>Returns a <see cref="MemoryStream"/> object, the contents of which is the same as the
        /// one in <paramref name="stream"/>.</summary>
        /// <param name="stream">The stream to read from.</param>
        /// <param name="bufferSize">The size of the temporary buffer used to copy the stream content.</param>
        /// <param name="initialCapacity">The initial capacity of the returned stream.</param>
        /// <remarks>By calling this method, <paramref name="stream"/> is put into the possession of this method. The
        /// caller must not access it in any way afterwards. Likewise, the returned <see cref="MemoryStream"/> object is
        /// put into the possession of the caller, so the caller is responsible for properly disposing it.</remarks>
        internal static MemoryStream ToMemoryStream(Stream stream, int bufferSize, int initialCapacity)
        {
            var result = stream as MemoryStream;

            if (result != null)
            {
                return result;
            }

            using (stream)
            {
                result = new MemoryStream(initialCapacity);
                Copy(stream, result, new byte[bufferSize]);
            }

            result.Seek(0, SeekOrigin.Begin);
            return result;
        }
    }
}
